package vno.fux.map
{
	import flash.display.Sprite;
	import flash.events.Event;
	import flash.events.EventDispatcher;
	import flash.events.MouseEvent;
	import flash.geom.Point;
	import flash.utils.getTimer;
	
	import vno.fux.BasePoint;
	import vno.fux.CompassDirection;
	import vno.fux.GlobalEventScheduler;
	import vno.fux.GlobalVar;
	import vno.fux.events.MapEvent;
	import vno.ky.seek.Deal;
	import vno.ky.seek.RoadClass;
	import vno.ky.seek.Sort;
	
	public class MapController extends EventDispatcher
	{
		private var _model:MapModel;
		private var _nowDes:BasePoint;
		private var _desPoint:BasePoint;
		private var _speedX:Number;
		private var _speedY:Number;
		private var _walkArray:Array;
		private var deal:Deal


		public function MapController(model_:MapModel)
		{
			_model = model_;
			deal = new Deal;
			deal.set(_model.gridMatrix);
			//setCoor();
		}

		public function handleClick(evt:MouseEvent):void
		{
			_desPoint = new BasePoint(
				_model.ox-(evt.target.stage.stageWidth/2 - evt.stageX), _model.oy-(evt.target.stage.stageHeight/2 - evt.stageY));
			//var desReachable:Boolean = (_model.gridMatrix[_desPoint.x][_desPoint.y]==0);
			//trace(_model.gridMatrix[_desPoint.x][_desPoint.y]);
			if(!desReachable())
			{
				var tryP:BasePoint = findReachable(_desPoint);
				if(!tryP)
				{
					dispatchEvent(new MapEvent(MapEvent.UNREACH, {pos:new BasePoint(evt.stageX, evt.stageY)}));
					trace("unreach");
					return;
				}
				_desPoint = tryP;
			}
			_walkArray = roadSeek(_model.oPoint,_desPoint);
			_nowDes = _walkArray.shift();
			moveInit();
			dispatchEvent(new MapEvent(MapEvent.START_MOVE, {start:_model.oPoint,end:_desPoint}));
			GlobalEventScheduler.getInstance().addEnterFrameListener(updateHandler);
		}
		
		private function findReachable(desPoint_:BasePoint):BasePoint
		{
			trace("findReachable");
			var gridPoint:BasePoint = convCoo2Grid(desPoint_);
			var result:BasePoint = null;
			outloop: for(var i:int=-1; i<=1; i++)
			{
				for(var j:int=-1; j<=1; j++)
				{
					try
					{
						if(!(_model.gridMatrix[gridPoint.x+i][gridPoint.y+j]==1))
						{
							gridPoint.x+=i;
							gridPoint.y+=j;
							result = gridPoint;
							break outloop;
						}
					}
					catch(re:RangeError)
					{
						continue;
					}
				}
			}
			return result?convGrid2Coo(result):null;
		}
		public function setCoor(coor_:BasePoint):void
		{
			_model.ox = coor_.x;
			_model.oy = coor_.y;
			_model.update();
			dispatchEvent(new MapEvent(MapEvent.START_MOVE, {start:_model.oPoint, end:_model.oPoint}));
			dispatchEvent(new MapEvent(MapEvent.MOVE, {pos:_model.oPoint}));
			dispatchEvent(new MapEvent(MapEvent.END_MOVE, {pos:_model.oPoint}));
		}
		
		private function roadSeek(oPoint:BasePoint, desPoint:BasePoint):Array
		{

			var gridO:BasePoint = convCoo2Grid(oPoint);
			var gridD:BasePoint = convCoo2Grid(desPoint);
			if(gridO.equals(gridD))
			{
				var ar:Array = [oPoint, desPoint];
				return ar;
			}
			//var a:Number = getTimer();
			var result:Array = deal.seek(gridO.x, gridO.y, gridD.x, gridD.y);
			for(var i:int=0; i<result.length; i++)
			{
				result[i] = convGrid2Coo(result[i]);
			}
			result.shift();
			//var b:Number = getTimer();
			//trace(b-a);
//			var ar:Array = [desPoint];
			//			trace(ar);
			return result;
		}
		
		private function desReachable():Boolean
		{
			var gridPoint:BasePoint = convCoo2Grid(_desPoint);
			try
			{
				var desReachable:Boolean = !(_model.gridMatrix[gridPoint.x][gridPoint.y]==1);
			}
			catch(re:RangeError)
			{
				return false;
			}
			//trace(_desPoint, gridPoint);
			return desReachable;
		}
		
		private function moveInit():void
		{
			var distanceX:Number;
			var distanceY:Number;
			//var oPoint:BasePoint = new BasePoint(_model.ox, _model.oy);
			var distance:BasePoint = _nowDes.subtract2(_model.oPoint);
			var direction_:String = judgeDirection(distance.x, distance.y);
			if(distance.length!=0)
			{
				_speedX = _model.speed*distance.x/distance.length;
				_speedY = _model.speed*distance.y/distance.length;
			}
			else
			{
				_speedX = _speedY = 0;
			}
			dispatchEvent(new MapEvent(MapEvent.DIRECTION, {direction:direction_}));
		}

		/**
		 * 转换函数，将实际坐标转换为路点坐标
		 * */
		private function convCoo2Grid(coo:BasePoint):BasePoint
		{
			
			var gridP:BasePoint = new BasePoint;
			gridP.x = int(coo.x/_model.gridCellSize);
			gridP.y = int(coo.y/_model.gridCellSize);
			/*if(_model.gridMatrix[gridP.x][gridP.y]==1)
			{
				outloop: for(var i=-2; i<=2; i++)
				{
					for(var j=-2; j<=2; j++)
					{
						if(_model.gridMatrix[gridP.x+i][gridP.y+j]==0)
						{
							gridP.x+=i;
							gridP.y+=j;
							break outloop;
						}
					}
				}
			}*/
			return gridP;
		}
		/**
		 * 转换函数，将路点坐标转换为实际坐标
		 * */
		private function convGrid2Coo(grid:Point):BasePoint
		{
			var cooP:BasePoint = new BasePoint;
			cooP.x = grid.x*_model.gridCellSize+_model.gridCellSize/2;
			cooP.y = grid.y*_model.gridCellSize+_model.gridCellSize/2;
			return cooP;
		}
		private function judgeDirection(_distanceX:Number, _distanceY:Number):String
		{
			if(_distanceX==0 && _distanceY==0)
			{
				return CompassDirection.CENTER;
			}
			var angle:Number = Math.atan2(_distanceY, _distanceX);
			var Pi:Number = Math.PI;
			if((angle >= 0 && angle <= Pi/6)||(angle < 0 && angle > -Pi/6))
			{
				return CompassDirection.E;
			}
			if(angle > Pi/6 && angle <= Pi/3)
			{
				return CompassDirection.SE;
			}
			if(angle > Pi/3 && angle <= Pi*2/3)
			{
				return CompassDirection.S;
			}
			if(angle > Pi*2/3 && angle <= Pi*5/6)
			{
				return CompassDirection.SW;
			}
			if((angle > Pi*5/6 && angle <= Pi)||(angle < -Pi*5/6 && angle >= -Pi))
			{
				return CompassDirection.W;
			}
			if(angle > -Pi*5/6 && angle <= -Pi*2/3)
			{
				return CompassDirection.NW;
			}
			if(angle > -Pi*2/3 && angle <= -Pi/3)
			{
				return CompassDirection.N;
			}
			if(angle > -Pi/3 && angle <= -Pi/6)
			{
				return CompassDirection.NE;
			}
			return CompassDirection.CENTER;
		}
		private function updateHandler(evt:Event):void
		{
			var detaX:Number = Math.abs(_model.ox - _nowDes.x);
			var detaY:Number = Math.abs(_model.oy - _nowDes.y);
			var flag:int = 0;
			var newX:Number = detaX<=Math.abs(_speedX)?(flag |= 0x1,_nowDes.x) : _model.ox+_speedX;
			var newY:Number = detaY<=Math.abs(_speedY)?(flag |= 0x2,_nowDes.y) : _model.oy+_speedY;
			
			_model.ox = newX;
			_model.oy = newY;
			var gridPosNow:BasePoint = convCoo2Grid(new BasePoint(newX, newY));
			var roadValue:int = _model.gridMatrix[gridPosNow.x][gridPosNow.y];
			if(flag == 0x3)
			{
				_nowDes = _walkArray.shift();
				if(!_nowDes)
				{
					GlobalEventScheduler.getInstance().removeEnterFrameListener(updateHandler);
					dispatchEvent(new MapEvent(MapEvent.END_MOVE, {pos:_model.oPoint}));
					return;
				}
				moveInit();
			}
			dispatchEvent(new MapEvent(MapEvent.MOVE, {pos:_model.oPoint, roadValue:roadValue}));
			_model.update();
		}
	}
}